package com.framework.oauthclient.util;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.framework.common.exception.BusinessException;
import com.framework.common.model.UserInfo;
import com.framework.common.util.RedisUtil;
import com.framework.common.util.SpringUtils;
import com.framework.common.util.StringUtils;
import com.framework.oauthclient.ext.ClientAuthenticationManager;
import com.framework.oauthclient.vo.ClientProperties;
import com.framework.oauthclient.vo.OAuthTokenResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class OauthClient {
    private Logger logger = LoggerFactory.getLogger(OauthClient.class);
    @Autowired
    private ClientProperties properties;

    public OAuthTokenResult getToken(String username, String password) {
        String uri = properties.getTokenUri();
        logger.info("连接授权服务器：{}", uri);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("grant_type", "password");
        paramMap.put("username", username);
        paramMap.put("password", password);
        paramMap.put("scope", properties.getScope().iterator().next());
        HttpResponse response = HttpRequest.post(uri)
                .basicAuth(properties.getClientId(), properties.getClientSecret())
                .form(paramMap)
                .execute();
        String result = response.body();
        if (response.isOk()) {
            logger.info(result);
            OAuthTokenResult ret = JSONObject.parseObject(result, OAuthTokenResult.class);
            if (StringUtils.isNotBlank(ret.getMsg())) {
                throw new BusinessException(ret.getMsg());
            }
            cacheRefreshToken(ret);
            return ret;
        } else {
            JSONObject object = null;
            try {
                object = JSONObject.parseObject(result);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }

            if (null != object && null != object.get("error")) {
                // spring 默认会校验error 这个字段， 所以这边名称和它一样
                throw new BusinessException(String.valueOf(object.get("error")));
            } else {
                throw new BusinessException("连接超时！");
            }
        }
    }

    public UserInfo userInfo(String token) {
        HttpResponse response = HttpRequest.get(properties.getUserInfoUri())
                .header("Authorization",  String.format("%s %s", "Bearer", token))
                .execute();
        if (response.isOk()) {
            String result = response.body();
            logger.info(result);
            UserInfo userInfo = JSON.parseObject(result, UserInfo.class);
            // 放入缓存
            cacheUserInfo(token, userInfo);
            return userInfo;
        } else {
            throw new RuntimeException("授权服务器获取用户信息出错!"+response.body());
        }
    }

    public UserInfo userInfoByDeptId(String token, String deptId) {
        HttpResponse response = HttpRequest.get(properties.getUserInfoUri())
                .header("Authorization",  String.format("%s %s", "Bearer", token))
                .form("deptId", deptId)
                .execute();
        if (response.isOk()) {
            String result = response.body();
            logger.info(result);
            UserInfo userInfo = JSON.parseObject(result, UserInfo.class);
            return userInfo;
        } else {
            throw new RuntimeException("授权服务器获取用户信息出错!"+response.body());
        }
    }

    public OAuthTokenResult refreshToken(OAuthTokenResult refreshToken) {
        String uri = properties.getTokenUri();
        logger.info("连接授权服务器：{}", uri);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("grant_type", "refresh_token");
        paramMap.put("refresh_token", refreshToken.getRefreshToken());
        HttpResponse response = HttpRequest.post(uri)
                .basicAuth(properties.getClientId(), properties.getClientSecret())
                .form(paramMap)
                .execute();
        String result = response.body();
        if (response.isOk()) {
            logger.info(result);
            OAuthTokenResult ret = JSONObject.parseObject(result, OAuthTokenResult.class);
            if (StringUtils.isNotBlank(ret.getMsg())) {
                throw new BusinessException(ret.getMsg());
            }
            cacheRefreshToken(ret);
            return ret;
        } else {
            JSONObject object = null;
            try {
                object = JSONObject.parseObject(result);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }

            if (null != object && null != object.get("code")) {
                // spring 默认会校验error 这个字段， 所以这边名称和它一样
                throw new BusinessException(String.valueOf(object.get("error")));
            } else {
                throw new BusinessException("刷新token失败！");
            }
        }
    }

    public void cacheRefreshToken(OAuthTokenResult ret) {
        // 重新设置一下redis缓存
        String token = ret.getAccessToken();
        RedisUtil redisUtil = SpringUtils.getBean(RedisUtil.class);
        // RefreshToken 缓存时间比Token过期时间多5分钟
        redisUtil.set(ClientAuthenticationManager.prefixRefreshKey.concat(token), ret, ret.getExpiresIn()+300);
    }

    public void cacheUserInfo(String token, UserInfo userInfo) {
        RedisUtil redisUtil = SpringUtils.getBean(RedisUtil.class);
        OAuthTokenResult ret = redisUtil.get(ClientAuthenticationManager.prefixRefreshKey.concat(token));
        redisUtil.set(token, userInfo, ret.getExpiresIn());
    }
}
